/****************************************************************************
 *
 * Copyright (C) 2003-2008 Los Alamos National Security, LLC
 *                         Packet Analytics Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2 as
 * published by the Free Software Foundation.  You may not use, modify or
 * distribute this program under any other version of the GNU General
 * Public License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 ****************************************************************************/
package nfse;

import java.io.*;

/*********
 * This is an abstract class that must be extended to implement file processing
 * capabilities. See examples nfse.NumericIndexFileProcessor and
 * nfse.stats.StatsFileProcessor.
 * 
 * @author bduphoff
 * 
 */

public abstract class DataFileProcessor extends Thread {

	/*************
	 * The absolute path of the file being processed from the system metadata.
	 */
	private String filePath = "";

	/*********************
	 * 8 The ID of the file being processed for this sensor in the system
	 * metadata.
	 */
	private int fileID = -1;

	/*********************
	 * The sensor ID associated with this instance.
	 */
	private int sensorID = -1;

	/************
	 * The byte offset in the file where processing last left off.
	 */
	private int offset = 0;

	/******
	 * The file processing status of this file from the system metadata.
	 */
	private int status = 0;

	/********************
	 * The app name from the system metadata.
	 */
	private String appName = "";

	/***************
	 * The app ID from the system metadata.
	 */
	private int appID = -1;

	/*************
	 * The input byte stream of the file being processed.
	 */
	private DataInputStream in = null;

	/******************
	 * The monitor thread that spawned this thread.
	 */
	private DataFileMonitor parent = null;

	/*****************
	 * Returns the parent DataFileMonitor.
	 * 
	 * @return The DataFIleMonitor thread that spawned this instance.
	 */
	public DataFileMonitor getDataFileMonitor() {
		return parent;
	}

	/**********************
	 * Set the app ID.
	 * 
	 * @param appID
	 *            The application ID from the system metadata
	 */
	public void setAppID(int appID) {
		this.appID = appID;
	}

	public int getAppID() {
		return appID;
	}

	public void setFileID(int fileID) {
		this.fileID = fileID;
	}

	public int getFileID() {
		return fileID;
	}

	public void setDataFileMonitor(DataFileMonitor dataFileMonitor) {
		this.parent = dataFileMonitor;
	}

	public String getAppName() {
		return appName;
	}

	public int getStatus() {
		return status;
	}

	public int getOffset() {
		return offset;
	}

	public int getSensorID() {
		return sensorID;
	}

	public String getFilePath() {
		return filePath;
	}

	public void setAppName(String appName) {
		this.appName = appName;
	}

	public void setOffset(int offset) {
		this.offset = offset;
	}

	public void setStatus(int status) {
		this.status = status;
	}

	public void setSensorID(int sensorID) {
		this.sensorID = sensorID;
	}

	public void setFilePath(String path) {
		filePath = path;
	}

	public void run() {
		try {
			in = new DataInputStream(new FileInputStream(filePath));
			process();
			in.close();
			parent.setFileProcessed(fileID);
		} catch (Exception e) {
			try {
				in.close();
			} catch (IOException ioe) {
				// no op
			}
			e.printStackTrace();
		}
	}

	/********************
	 * A checkpoint in the file can be stored in the metadata. This method
	 * returns the file pointer to the last point of reference.
	 * 
	 * @throws Exception
	 */
	public void moveToOffset() throws IOException {
		if (in != null) {
			in.close();
		}
		in = new DataInputStream(new FileInputStream(filePath));
		int currentOffset = 0;
		while (currentOffset < offset) {
			int len = in.readInt();
			byte[] bytes = new byte[len];
			in.read(bytes);
			currentOffset++;
		}
	}

	/***************
	 * Reads the next record of the file being processed.
	 * 
	 * @return The bytes of the record that was read.
	 * @throws Exception
	 */
	public byte[] getNextRecord() throws IOException {
		try {
			// First read the length of the record to read
			int len = in.readInt();

			int bytesRead = 0;
			byte[] dataBytes = new byte[len];

			/***********************************************************
			 * Read bytes from the socket connection into an array (dataBytes)
			 * of length len until the specified length is met.
			 */
			while (bytesRead < len)
				bytesRead += in.read(dataBytes, bytesRead, len - bytesRead);

			offset++;
			return dataBytes;
		} catch (java.io.EOFException e) {
			// no op
		}
		return null;
	}

	/******************
	 * This method must be implemented by all extending DataFileProcessor
	 * classes. This method is called from run() and must handle the reading of
	 * records and the updating of system metadata.
	 * 
	 * See StatsFileProcessor for an example of how a DataFileProcessor can be
	 * implemented.
	 */
	public abstract void process();

}
